import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.herohead.CDLogger;
import com.herohead.Misc;
import com.herohead.Rabbit_publish;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;


public class AV_DailyReports {

	public static PreparedStatement SQL = null;
	private static org.apache.log4j.Logger log= Logger.getLogger(AV_DailyReports.class);

	static Connection connection = null;

	private static Options createOptions() {
		Options options = new Options();
		options.addOption("h", "help", false, "print this message and exit");
		options.addOption("c", "config", true, "Configuration file");
		return options;
	}

	private static void showHelp(Options options) {
		HelpFormatter h = new HelpFormatter();
		h.printHelp("help", options);
		System.exit(-1);
	}


	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub

		

		
		String configFile = null;
		final CDLogger l = new CDLogger();
		
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() { 
				l.programStop(log);
			}
		});
		
		
		l.programStart(log);

		Options options = createOptions();
		try {
			CommandLineParser parser = new PosixParser();
			CommandLine cmd = parser.parse(options, args);
			if (cmd.hasOption("h")) {
				showHelp(options);
			}     

			if (cmd.hasOption("h")) showHelp(options);	  
			if (cmd.hasOption("c")) {
				configFile = cmd.getOptionValue("c"); 
			} else {
				showHelp(options);
			} 

		} catch (Exception e) {
			e.printStackTrace();
			showHelp(options);
		}


		String AvamarLookupDate = null;
		String className = "AV_DailyReports";
		PropertiesConfiguration config = new PropertiesConfiguration(configFile);
		config.setAutoSave(false);

		String SQLConnection = config.getString("SQLConnection");
		String SQLUser = config.getString("SQLUser");
		String SQLPassword = config.getString("SQLPassword");
		String server = config.getString("server");
		String sourceSystem = config.getString("sourceSystem");
		String log4jPropFile = config.getString("log4jPropFile");

		String rabbitmqserver = config.getString("rabbitmqserver");
		String RMQQueue = config.getString("RMQQueue");
		String RMQVirtualHost= config.getString("RMQVirtualHost"); 
		String RMQUsername= config.getString("RMQUsername");
		String RMQPassword= config.getString("RMQPassword");
		
		
		if (!config.containsKey("AvamarLookupDate")) {
			config.setProperty("AvamarLookupDate", "2013-07-01 00:00:00");
			AvamarLookupDate = "2013-07-01 00:00:00";
			log.info("Looks like program has never run - setting start search date to 2013-07-01 00:00:00");
		}
		AvamarLookupDate = config.getString("AvamarLookupDate");
		//config.setProperty("AvamarLookupDate", "2013-08-28 12:00:00");
		//System.out.println(config.getString("AvamarLookupDate"));
		//		AvamarLookupDate = removeMilli(AvamarLookupDate);

		//System.out.println(config.getString("AvamarLookupDate"));
		//System.out.println(config.getString("AvamarLookupDate"));

		log.debug("Reading configuration file - " + className + ".config" );

		Class.forName("org.postgresql.Driver");
		connection = DriverManager.getConnection(SQLConnection,SQLUser, SQLPassword);

		String sqlString = "Select recorded_date, recorded_time, recorded_date_time ,client_name, plugin_name, status_code, error_code, status_code_summary, domain,group_name,Client_os,started_time,started_date, completed_date, completed_time, bytes_new,bytes_scanned,num_of_files,started_ts " +
				"from v_activities_2 " +
				"where recorded_date_time > " + "'" + AvamarLookupDate + "'" +
				"order by recorded_date_time asc";

		SQL = connection.prepareStatement(sqlString);

		ResultSet resultSet = SQL.executeQuery();

		String lastUpdate = null;

		Rabbit_publish rmq = new Rabbit_publish();
		rmq.setHostname(rabbitmqserver);
		rmq.setLogin(RMQVirtualHost, RMQPassword, RMQUsername);
		Channel ch = rmq.setupChannel();


		AMQP.BasicProperties properties = new AMQP.BasicProperties();
		properties.setDeliveryMode(2);

		boolean durable = true;

		ch.queueDeclare(RMQQueue, durable, false, false, null);


		int cc =0;

		while (resultSet.next()) {
			cc++;
			//System.out.println(resultSet.getString("client_name") + " " + resultSet.getString("recorded_date_time"));
			lastUpdate = resultSet.getString("recorded_date_time");
			String started_ts = resultSet.getString("recorded_date_time");
			config.setProperty("AvamarLookupDate", lastUpdate);

			String client_name = resultSet.getString("client_name");
			String saveGroup = resultSet.getString("group_name");
			String client_status = resultSet.getString("error_code");

			//String st = resultSet.getString("started_time");
			//String ct = resultSet.getString("completed_time");

			String starttime = resultSet.getString("started_date") + " " + resultSet.getString("started_time");
			String endTime = resultSet.getString("completed_date") + " " + resultSet.getString("completed_time");

			//			String starttime = resultSet.getString("started_date") + " " + removeMilli(resultSet.getString("started_time"));
			//			String endTime = resultSet.getString("completed_date") + " " + removeMilli(resultSet.getString("completed_time"));


			//System.out.println(starttime);

			if (client_status.contentEquals("0")) client_status = "Succeeded";
			else client_status = "Failed";

			String numberOfFiles = resultSet.getString("num_of_files");
			String bytesScanned = resultSet.getString("bytes_scanned");
			String newBytes = resultSet.getString("bytes_new");
			String clientPerCentNew;

			if (Long.parseLong(bytesScanned) == 0 || Long.parseLong(newBytes) == 0) {
				clientPerCentNew = "0";
			} else {
				float clientPerCentNewlong = Float.parseFloat(newBytes) / Float.parseFloat(bytesScanned) * 100;
				clientPerCentNew = Float.toString(clientPerCentNewlong);
			}
			String details = "";

			String xml = formatXML(server,sourceSystem,saveGroup,starttime,endTime,client_name,client_status,details,numberOfFiles,bytesScanned,newBytes,clientPerCentNew,started_ts,"Full");
			//System.out.println(xml);
			//readXML(xml);

			ch.basicPublish("", RMQQueue, properties, xml.getBytes());
			log.info(cc + "  Sending " + client_name + " " + started_ts );

			if (lastUpdate != null) {
				config.setProperty("AvamarLookupDate", lastUpdate);
			}
		}

		if (cc > 0 ) {
			Channel totals = rmq.setupChannel();
			//properties = new AMQP.BasicProperties();
			properties.setDeliveryMode(2);
			totals.queueDeclare("Totals_log", durable, false, false, null);
			/* sourceSystem = sourceSystem
			 * type = publish
			 * publichedCount = count
			 */


			String xml= formatTotalsXML(sourceSystem,Integer.toString(cc),"published",Misc.getTimestamp());
			totals.basicPublish("", "Totals_log", properties, xml.getBytes());

		}

		config.save();


		rmq.closeChannel();
		connection.close();
		System.exit(0);

	}

	private static String ToString(int cc) {
		// TODO Auto-generated method stub
		return null;
	}

	public static String formatXML(String system, String sourceSystem,String savegroupName, String savegroupStartTime, String savegroupEndTime,  String client, String status, String clientDetails,String numberOfFiles,String bytesScanned, String newBytes, String clientPerCentNew, String started_ts ,String backupType) throws TransformerException{

		String timeStamp = Misc.getTimestamp();
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

			// root elements
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement("savegrouplog");
			doc.appendChild(rootElement);
			Element e0 = doc.createElement("timestamp");
			e0.appendChild(doc.createTextNode(timeStamp));
			rootElement.appendChild(e0);
			Element es = doc.createElement("system");
			es.appendChild(doc.createTextNode(system));
			rootElement.appendChild(es);
			Element es1 = doc.createElement("sourceSystem");
			es1.appendChild(doc.createTextNode(sourceSystem));
			rootElement.appendChild(es1);
			Element e = doc.createElement("saveGroupName");
			e.appendChild(doc.createTextNode(savegroupName));
			rootElement.appendChild(e);
			Element e1 = doc.createElement("saveGroupStatus");
			e1.appendChild(doc.createTextNode(""));
			rootElement.appendChild(e1);
			Element e2 = doc.createElement("saveGroupStartTime");
			e2.appendChild(doc.createTextNode(savegroupStartTime));
			rootElement.appendChild(e2);
			Element e3 = doc.createElement("saveGroupEndTime");
			e3.appendChild(doc.createTextNode(savegroupEndTime));
			rootElement.appendChild(e3);
			Element e4 = doc.createElement("saveGroupRestartTime");
			e4.appendChild(doc.createTextNode(""));
			rootElement.appendChild(e4);
			Element e5 = doc.createElement("saveGroupClientCount");
			e5.appendChild(doc.createTextNode(""));
			rootElement.appendChild(e5);
			Element e5a = doc.createElement("saveGroupClientList");
			e5a.appendChild(doc.createTextNode(""));
			rootElement.appendChild(e5a);
			Element e6 = doc.createElement("clientlist");
			e6.appendChild(doc.createTextNode(""));
			rootElement.appendChild(e6);
			Element e7 = doc.createElement("clientName");
			e7.appendChild(doc.createTextNode(client));
			rootElement.appendChild(e7);
			Element e8 = doc.createElement("clientStatus");
			e8.appendChild(doc.createTextNode(status));
			rootElement.appendChild(e8);
			Element e9 = doc.createElement("clientDetails");
			e9.appendChild(doc.createTextNode(clientDetails));
			rootElement.appendChild(e9);
			Element e9a = doc.createElement("clientFileCount");
			e9a.appendChild(doc.createTextNode(numberOfFiles));
			rootElement.appendChild(e9a);
			Element e9a1 = doc.createElement("clientBytesScanned");
			e9a1.appendChild(doc.createTextNode(bytesScanned));
			rootElement.appendChild(e9a1);
			Element e9a2 = doc.createElement("clientNewBytes");
			e9a2.appendChild(doc.createTextNode(newBytes));
			rootElement.appendChild(e9a2);
			Element e9a3 = doc.createElement("clientPerCentNew");
			e9a3.appendChild(doc.createTextNode(clientPerCentNew));
			rootElement.appendChild(e9a3);
			Element e9a4 = doc.createElement("started_ts");
			e9a4.appendChild(doc.createTextNode(started_ts));
			rootElement.appendChild(e9a4);
			 Element bT = doc.createElement("backupType");
			 bT.appendChild(doc.createTextNode(backupType));
			 rootElement.appendChild(bT);

			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();

			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new StringWriter());
			transformer.transform(source, result);
			//System.out.println(result.getWriter().toString());

			return result.getWriter().toString();

		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
			return pce.toString();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return e.toString();
		}
	}
	public static String formatTotalsXML(String sourceSystem,String count, String type, String timestamp ) throws TransformerException{

		String timeStamp = Misc.getTimestamp();
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

			// root elements
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement("totals_log");
			doc.appendChild(rootElement);
			Element e0 = doc.createElement("sourceSystem");
			e0.appendChild(doc.createTextNode(sourceSystem));
			rootElement.appendChild(e0);
			Element es = doc.createElement("count");
			es.appendChild(doc.createTextNode(count));
			rootElement.appendChild(es);
			Element es1 = doc.createElement("type");
			es1.appendChild(doc.createTextNode(type));
			rootElement.appendChild(es1);
			Element est = doc.createElement("timestamp");
			est.appendChild(doc.createTextNode(timestamp));
			rootElement.appendChild(est);

			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();

			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new StringWriter());
			transformer.transform(source, result);
			//System.out.println(result.getWriter().toString());

			return result.getWriter().toString();

		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
			return pce.toString();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return e.toString();
		}
	}

	public static String checkNull(String s,boolean str) {
		if (s.length() == 0) 
			if (str) s = null;
			else s = "0";
		return s;
	}

	public static String removeMilli(String st) {
		if (st.indexOf(".") != -1) {
			return st.substring(0,st.indexOf("."));
		} else {
			return st;
		}

	}


}
